package edu.tgc.security;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import edu.tgc.entity.system.SysDept;
import edu.tgc.entity.system.SysDeptPosition;
import edu.tgc.entity.system.SysDuty;
import edu.tgc.entity.system.SysUser;
import edu.tgc.repository.system.SysDeptRepository;
import edu.tgc.repository.system.SysUserRepository;

@Service
public class Security {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    protected SysUserRepository sysUserRepository;
    @Autowired
    protected SysDeptRepository sysDeptRepository;

    public Authentication getAuthentication() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Assert.notNull(authentication, "Authentication required");
        return authentication;
    }

    public SessionUser getSessionUser() {
        Authentication authentication = getAuthentication();
        Assert.notNull(authentication.getPrincipal(), "Principal required");
        if (authentication.getPrincipal() instanceof SessionUser) {
            return (SessionUser) authentication.getPrincipal();
        } else {
            return null;
        }
    }

    public SysUser getUser() {
        SessionUser sessionUser = getSessionUser();
        if (sessionUser == null || getSessionUser().getId() == null) {
            return null;
        } else {
            return this.sysUserRepository.findOne(getSessionUser().getId());
        }
    }

    public String getUsername() {
        Authentication authentication = getAuthentication();
        Assert.notNull(authentication.getPrincipal(), "Principal required");
        if (authentication.getPrincipal() instanceof SessionUser) {
            return ((UserDetails) authentication.getPrincipal()).getUsername();
        } else {
            return authentication.getPrincipal().toString();
        }
    }

    public boolean hasDuty(SysDept dept, String duty) {
        return hasDuty(dept.getId(), duty);
    }

    public boolean hasDuty(UUID deptId, String duty) {
        SysUser sysUser = getUser();
        if (sysUser != null) {
            for (SysDeptPosition sysDeptPosition : sysUser.getDeptPositions()) {
                if (deptId.equals(sysDeptPosition.getDept().getId())) {
                    if (sysDeptPosition.getPosition().getEnabled()) {
                        for (SysDuty sysDuty : sysDeptPosition.getPosition().getDuties()) {
                            if (sysDuty.getEnabled() && sysDuty.getCodePath().equals(duty)) {
                                if (this.logger.isDebugEnabled()) {
                                    this.logger.debug("对编号" + deptId + "部门具有" + duty + "职责");
                                }
                                return true;
                            }
                        }
                    }
                }
            }
        }
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("对编号" + deptId + "部门具有" + duty + "职责");
        }
        return false;
    }

    public boolean hasDuty(String duty) {
        SysUser sysUser = getUser();
        if (sysUser != null) {
            for (SysDeptPosition sysDeptPosition : sysUser.getDeptPositions()) {
                for (SysDuty sysDuty : sysDeptPosition.getPosition().getDuties()) {
                    if (sysDuty.getCodePath().equals(duty)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public List<SysDept> getDeptByDuty(UUID userId, String duty) {
        return sysDeptRepository.findByDuty(userId, duty);
    }

    public Set<SysDept> getDeptByDuty(String codePath) {
        SysUser sysUser = getUser();
        Set<SysDept> depts = new HashSet<>();
        if (sysUser != null) {
            for (SysDeptPosition sysDeptPosition : sysUser.getDeptPositions()) {
                for (SysDuty sysDuty : sysDeptPosition.getPosition().getDuties()) {
                    if (sysDuty.getCodePath().equals(codePath)) {
                        depts.add(sysDeptPosition.getDept());
                        break;
                    }
                }
            }
        }
        return depts;
    }

    public boolean hasRole(String role) {
        return getAuthentication().getAuthorities().contains(new SimpleGrantedAuthority(getRoleWithDefaultPrefix("ROLE_", role)));
    }

    private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) {
        if (role == null) {
            return role;
        }
        if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) {
            return role;
        }
        if (role.startsWith(defaultRolePrefix)) {
            return role;
        }
        return defaultRolePrefix + role;
    }
}
